#include <string.h>
#include <unistd.h>
#include<string.h>

#include <iostream>
#include <string>
#include <fstream>

#include "cJSON.h"
#include "zmq.h"

using namespace std;

#define SUMMARY_EVERY_US 1000000
#define FrameSize  3*1024*1024
#define PARAM_SIZE 1024
#define RATE_LIMIT  1

static char *buffer_send = NULL;

typedef struct Model
{
    char param[PARAM_SIZE];
    char data[FrameSize];
}Model;


int readJPG(int8_t** buf)
{
    FILE* pf = fopen("test.png", "r");
    fseek(pf, 0, SEEK_END);
    int length = ftell(pf);
    *buf = (int8_t*)malloc(length);
    fseek(pf, 0, SEEK_SET);
    fread(*buf, length, 1, pf);
    return length;
}


int readRGB(int8_t** buf)
{
    FILE* pf = fopen("rgb.bin", "r");
    //fseek(pf, 0, SEEK_END);
    //int length = ftell(pf);
    int length = 720 * 1280 * 3;
    *buf = (int8_t*)malloc(length);
    fseek(pf, 0, SEEK_SET);
    fread(*buf, length, 1, pf);
    printf("length = %d\n", length);
    return length;
}


int BuildData(char* jsonData, int jsonDataLen, int8_t* imgData, int imgDataLen, int8_t **sendData)
{
    int totalLen = 12 + jsonDataLen + imgDataLen;
    *sendData = (int8_t*)malloc(totalLen);
    printf("toalLen = %d\n", totalLen);
    printf("jsonDataLen = %d\n", jsonDataLen);
    printf("imgDataLen = %d\n", imgDataLen);

    memset(*sendData, 0, totalLen);
    memcpy(*sendData, &totalLen, 4);
    memcpy(*sendData + 4, &jsonDataLen, 4);
    memcpy(*sendData + 8, &imgDataLen, 4);
    memcpy(*sendData + 12, jsonData, jsonDataLen);
    memcpy(*sendData + 12 + jsonDataLen, imgData, imgDataLen);

    return totalLen;

}

char* build_data_frame(int frame_len)
{
    char *pBuff = (char*)malloc(frame_len);
    int i = frame_len;
    for(i = 0; i < frame_len; i++)
    {
        pBuff[i] = i + 1;
    }
    return pBuff;
}


void free_frame_data(char *pBuff)
{
    free(pBuff);
    pBuff = NULL;
}


uint64_t now_microseconds(void) {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec;
}

void microsleep(int usec) {
  struct timespec req;
  req.tv_sec = 0;
  req.tv_nsec = 1000 * usec;
  nanosleep(&req, NULL);
}

//发布订阅模型，发布者
int publisher()
{
    void* context = zmq_ctx_new();
    void* publisher = zmq_socket(context, ZMQ_PUB);

    /* 修改socket 的收发缓冲区大小为 32M bytes */
    // int sendbuff = 32*1024*1024;
    // zmq_setsockopt(publisher, ZMQ_SNDBUF, (void *)&sendbuff, sizeof(int));
    // int recvbuff = 32*1024*1024;
    // zmq_setsockopt(publisher, ZMQ_RCVBUF, (void *)&recvbuff, sizeof(int));
 
    int ret = zmq_bind(publisher, "tcp://*:5558");
    buffer_send = build_data_frame(FrameSize);
 
    int i = 0;
    int sent = 0;
    uint64_t start_time = now_microseconds();
    uint64_t next_summary_time = start_time + SUMMARY_EVERY_US;
    int previous_sent = 0;
    uint64_t previous_report_time = start_time;



    while(1)
    {
        uint64_t now = now_microseconds();

        // Model model;
        // model.no = i;
        // memset(model.buf, 0x01, sizeof(model.buf)); 

        ret = zmq_send(publisher, (void*)buffer_send, FrameSize, 0);
        i++;

        sent++;
        if (now > next_summary_time)
        {
            int countOverInterval = sent - previous_sent;
            double intervalRate =countOverInterval / ((now - previous_report_time) / 1000000.0);
            printf("%d ms: Sent %d - %d since last report (%d Hz)\n",
                    (int)(now - start_time) / 1000, sent, countOverInterval,(int)intervalRate);

            previous_sent = sent;
            previous_report_time = now;
            next_summary_time += SUMMARY_EVERY_US;
        }


        while (((i * 1000000.0) / (now - start_time)) > RATE_LIMIT)
        {
            microsleep(2000);
            now = now_microseconds();
        }
    }
 
    zmq_close (publisher);
    zmq_ctx_destroy (context);
    free_frame_data(buffer_send);
 
    return 0;
}



//推拉模型，pusher
// int pusher()
// {
//     void* context = zmq_ctx_new();
//     void* pusher = zmq_socket(context, ZMQ_PUSH);
 
//     int ret = zmq_bind(pusher, "tcp://*:5558");
//     buffer_send = build_data_frame(FrameSize);
 
//     int i = 0;
//     int sent = 0;
//     uint64_t start_time = now_microseconds();
//     uint64_t next_summary_time = start_time + SUMMARY_EVERY_US;
//     int previous_sent = 0;
//     uint64_t previous_report_time = start_time;

//     Model model;

//     //构造data部分数据，即YUV数据
//     memset(model.data, 0x00, sizeof(model.data));
//     int size =readJPG(model.data);
//     printf("size %d\n", size);

//     //构造param部分数据
//     char* model_params = "\n\t{\n\t\t\t\"area\":[[[\"x1\",\"y1\"],[\"x2\",\"y2\"],[\"x3\",\"y3\"]], [[\"x1\",\"y1\"],[\"x2\",\"y2\"],[\"x3\",\"y3\"]]],\n\t\t\t\"conf_thr\": 0.5\n\t}";
//     cJSON *root;    
//     root = cJSON_CreateObject();
//     cJSON_AddNumberToObject(root,"seq_number", 666);
//     cJSON_AddNumberToObject(root,"timestamp", 123456);
//     cJSON_AddNumberToObject(root,"data_size", size);
//     cJSON_AddStringToObject(root,"device_id", "123");
//     cJSON_AddStringToObject(root,"channel_id", "456");
//     cJSON_AddRawToObject(root,"model_params", model_params);
//     char *out = cJSON_Print(root);
//     printf("%s\n", out);
//     memset(model.param, 0x00, sizeof(model.param)); 
//     printf("out len %d\n", strlen(out));
//     memcpy(model.param, out, PARAM_SIZE);

    
//     while(1)
//     {
//         uint64_t now = now_microseconds();
//         ret = zmq_send(pusher, (void*)&model, sizeof(model), 0);//发送数据
//         //ret = zmq_send(pusher, (void*)buffer_send, FrameSize, 0);;
//         i++;
//         sent++;
//         if (now > next_summary_time)
//         {
//             int countOverInterval = sent - previous_sent;
//             double intervalRate =countOverInterval / ((now - previous_report_time) / 1000000.0);
//             printf("%d ms: Sent %d - %d since last report (%d Hz)\n",
//                     (int)(now - start_time) / 1000, sent, countOverInterval,(int)intervalRate);

//             previous_sent = sent;
//             previous_report_time = now;
//             next_summary_time += SUMMARY_EVERY_US;
//         }

//         while (((i * 1000000.0) / (now - start_time)) > RATE_LIMIT)
//         {
//             microsleep(2000);
//             now = now_microseconds();
//         }
//     }

//     // 释放内存
//     free(out);
//     cJSON_Delete(root);
 
//     zmq_close (pusher);
//     zmq_ctx_destroy (context);
//     free_frame_data(buffer_send);
 
//     return 0;
// }


int pusher()
{
    void* context = zmq_ctx_new();
    void* pusher = zmq_socket(context, ZMQ_PUSH);
 
    int ret = zmq_bind(pusher, "tcp://*:5558");
    buffer_send = build_data_frame(FrameSize);
 
    int i = 0;
    int sent = 0;
    uint64_t start_time = now_microseconds();
    uint64_t next_summary_time = start_time + SUMMARY_EVERY_US;
    int previous_sent = 0;
    uint64_t previous_report_time = start_time;

    Model model;

    //构造data部分数据，即YUV数据
    int8_t *imgData = NULL;
    //int imgDataLen = readJPG(&imgData);
    int imgDataLen = readRGB(&imgData);
    printf("imgDataLen %d\n", imgDataLen);
    fstream ofs("out.png", ios::out | ios::binary);
    ofs.write((char*)imgData, imgDataLen);

    //构造param部分数据
    char* model_params = "\n\t{\n\t\t\t\"area\":[[[\"x1\",\"y1\"],[\"x2\",\"y2\"],[\"x3\",\"y3\"]], [[\"x1\",\"y1\"],[\"x2\",\"y2\"],[\"x3\",\"y3\"]]],\n\t\t\t\"conf_thr\": 0.5\n\t}";
    cJSON *root;    
    root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root,"seq_number", 666);
    cJSON_AddNumberToObject(root,"timestamp", 123456);
    cJSON_AddNumberToObject(root,"data_size", imgDataLen);
    cJSON_AddStringToObject(root,"device_id", "123");
    cJSON_AddStringToObject(root,"channel_id", "456");
    cJSON_AddStringToObject(root,"img_type", "RGB");
    cJSON_AddNumberToObject(root,"width", 1280);
    cJSON_AddNumberToObject(root,"height", 720);
    cJSON_AddRawToObject(root,"model_params", model_params);
    char *out = cJSON_Print(root);
    printf("%s\n", out);
    memset(model.param, 0x00, sizeof(model.param)); 
    printf("out len %d\n", strlen(out));
    //memcpy(model.param, out, PARAM_SIZE);
    int8_t *sendData = NULL;
    int sendDataLen = 0;
    sendDataLen = BuildData(out, strlen(out), imgData, imgDataLen, &sendData);
    printf("sendDataLen = %d\n", sendDataLen);

    
    while(1)
    {
        uint64_t now = now_microseconds();
        ret = zmq_send(pusher, (void*)sendData, sendDataLen, 0);//发送数据
        //ret = zmq_send(pusher, (void*)buffer_send, FrameSize, 0);;
        i++;
        sent++;
        if (now > next_summary_time)
        {
            int countOverInterval = sent - previous_sent;
            double intervalRate =countOverInterval / ((now - previous_report_time) / 1000000.0);
            printf("%d ms: Sent %d - %d since last report (%d Hz)\n",
                    (int)(now - start_time) / 1000, sent, countOverInterval,(int)intervalRate);

            previous_sent = sent;
            previous_report_time = now;
            next_summary_time += SUMMARY_EVERY_US;
        }

        while (((i * 1000000.0) / (now - start_time)) > RATE_LIMIT)
        {
            microsleep(2000);
            now = now_microseconds();
        }
    }

    // 释放内存
    free(out);
    cJSON_Delete(root);
 
    zmq_close (pusher);
    zmq_ctx_destroy (context);
    free_frame_data(buffer_send);
 
    return 0;
}



int main()
{
    pusher();

    return 0;
}